package com.blkj.iam.shared.sso.controller;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.sso.name.ParamName;
import cn.dev33.satoken.sso.processor.SaSsoServerProcessor;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.blkj.iam.common.constant.CommonConstant;
import com.blkj.iam.common.constant.SsoConstants;
import com.blkj.iam.common.util.JwtUtil;
import com.blkj.iam.shared.client.service.SsoUserService;
import com.blkj.iam.shared.sso.service.SsoService;
import com.blkj.iam.system.model.entity.User;
import com.blkj.iam.system.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * Sa-Token-SSO Server端 Controller
 *
 * @author click33
 */
@Slf4j
@RequiredArgsConstructor
@RestController
public class SsoController {

    private final RedisTemplate<String, Object> redisTemplate;
    private final UserService userService;
    private final SsoService ssoService;
    private final ParamName paramName = new ParamName();
    private final SsoUserService apiUserService;

    /**
     * SSO-Server端：处理所有SSO相关请求
     * http://{host}:{port}/sso/auth		-- 单点登录授权地址，接受参数：redirect=授权重定向地址
     * http://{host}:{port}/sso/doLogin		-- 账号密码登录接口，接受参数：name、pwd
     * http://{host}:{port}/sso/checkTicket	-- Ticket校验接口（isHttp=true时打开），接受参数：ticket=ticket码、ssoLogoutCall=单点注销回调地址 [可选]
     * http://{host}:{port}/sso/signout		-- 单点注销地址（isSlo=true时打开），接受参数：loginId=账号id、sign=参数签名
     */
    // SSO-Server：统一认证地址
    @RequestMapping("/sso/auth")
    public Object ssoAuth() {
        return SaSsoServerProcessor.instance.ssoAuth();
    }

    // SSO-Server：RestAPI 登录接口
    @RequestMapping("/sso/doLogin")
    public SaResult ssoDoLogin() {
//        return SaSsoServerProcessor.instance.ssoDoLogin();
        SaResult result = (SaResult) SaSsoServerProcessor.instance.ssoDoLogin();
        // 检查登录是否成功
        if (result.getCode() == 200) {
            // 获取登录后的用户 ID
            Object loginId = StpUtil.getLoginId();

            // 获取生成的 Token
            String token = StpUtil.getTokenValue();

            // 获取JwtToken
            Object object = redisTemplate.opsForValue().get(CommonConstant.CLIENT_USER_TOKEN + loginId);

            // 获取用户信息
            JSONObject loginUser = apiUserService.getLoginUser(loginId.toString());

            // 获取用户部门信息
            JSONObject userDepart = apiUserService.getLoginUserDepart(loginId.toString());

            // 自定义返回信息
            Map<String, Object> customData = new HashMap<>();
            customData.put(SsoConstants.LOGIN_ID, loginId);
            customData.put(SsoConstants.LOGIN_TOKEN, token);
            customData.put(SsoConstants.LOGIN_JWT_TOKEN, object);
            customData.put(SsoConstants.LOGIN_USER, loginUser);
            customData.put(SsoConstants.LOGIN_USER_DEPART, userDepart);
            customData.put(SsoConstants.MESSAGE, "登录成功，欢迎回来！");
            customData.put(SsoConstants.TIMESTAMP, System.currentTimeMillis());
            return SaResult.ok().setData(customData);
        } else {
            // 如果登录失败，直接返回原始结果
            return result;
        }
    }

    // SSO-Server：校验ticket 获取账号id
    @RequestMapping("/sso/checkTicket")
    public Object ssoCheckTicket() {
        String ssoLogoutCall = SaHolder.getRequest().getParamMap().get("ssoLogoutCall");
        log.info("ssoLogoutCall: {}", ssoLogoutCall);
        return SaSsoServerProcessor.instance.ssoCheckTicket();
    }

    // SSO-Server：单点注销
    @RequestMapping("/sso/signout")
    public Object ssoSignOut() {
        String clientId = SaHolder.getRequest().getParam(paramName.client);
        String loginId = SaHolder.getRequest().getParam(paramName.loginId);
        log.info("SSO退出成功, 客户端ID:{}, 登录ID:{}", clientId, loginId);
        return SaSsoServerProcessor.instance.ssoSignout();
    }

    private static SaResult checkSign() {
        try {
            // 校验签名：只有拥有正确秘钥发起的请求才能通过校验
            String client = SaHolder.getRequest().getHeader(SsoConstants.CLIENT);
            SaSsoServerProcessor.instance.ssoServerTemplate.getSignTemplate(client).checkRequest(SaHolder.getRequest());
            return SaResult.ok();
        } catch (Exception e) {
            return SaResult.error("签名校验失败");
        }
    }

    // 获取登录信息
    @RequestMapping("/sso/getData")
    public SaResult getData(String loginId) {
        SaResult signResult = checkSign();
        if (signResult.getCode() != 200) {
            return signResult;
        }

        // 查询Token是否存在
        Object object = redisTemplate.opsForValue().get(CommonConstant.CLIENT_USER_TOKEN + loginId);
        if (ObjectUtil.isEmpty(object)) {
            return SaResult.error("请检查用户登录状态");
        }

        // 获取用户信息
        String tokenValue = object.toString();
        JSONObject data = new JSONObject();
        data.set(SsoConstants.LOGIN_ID, loginId);
        data.set(SsoConstants.LOGIN_JWT_TOKEN, tokenValue);
        String username = JwtUtil.getUsername(tokenValue);
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (ObjectUtil.isNotEmpty(user)) {
            data.set(SsoConstants.USERNAME, user.getUsername());
            data.set(SsoConstants.PASSWORD, user.getRawPass());
        } else {
            data.set(SsoConstants.USERNAME, null);
            data.set(SsoConstants.PASSWORD, null);
        }

        return SaResult.ok().setData(data);
    }

}
